package com.example.gl_project5;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Vector;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.renderscript.Matrix4f;

public class GlRenderer implements GLSurfaceView.Renderer {

	private final FloatBuffer mPyramid;
	
	private final FloatBuffer mFloor;
	
	private int MVPMatrixLocation;
	
	private int MVMatrixLocation;
	
	private float[] ProjectionMatrix = new float[16];
	
	private float[] CameraMatrix = new float[16];
	
	private long startTime;
	
	private float transformX = 0;
	
	private float transformY = 0;
	
	 
	private final int mBytesPerFloat = Float.SIZE/8;
	 
	
	private int mAmbientLightLocation;
	
	private int mPositionHandle;
	
	private int mNormalHandle;
	
	private int mMaterialAmbientColorLocation;
	
	private int mMaterialDiffuseColorLocation;
	
	private int mMaterialSpecularColorLocation;
	
	private int mMaterialSpecularExponentLocation;
     
    private final int mStrideBytes = 7 * mBytesPerFloat;
     
    private final int mPositionOffset = 0;
     
    private final int mPositionDataSize = 3;
     
    private final int mColorOffset = 3;
     
    private final int mColorDataSize = 4;
    
    private Light light1;
    
    private FloatBuffer pyramidNormalBuffer;
    
    private FloatBuffer floorNormalBuffer;
	 
	
	final String vertexShader = new VertexShader().toString();
			  
	 
	final String fragmentShader = new FragmentShader().toString();

	float[] pyramid;
	
	
	/**
	 * Initialize the model data.
	 */
	public GlRenderer()
	{
		
		float[] pyramid = {
				
				//blue triangle				
	            // X, Y, Z,
	            // R, G, B, A
	    		-1.0f, 1.0f, 0.0f,
	            0.0f, 0.0f, 1.0f, 1.0f,
	 
	            -1.0f, -1.0f, 0.0f,
	            0.0f, 0.0f, 1.0f, 1.0f,
	            
	            0.0f, 0.0f, 2.0f,
	            0.0f, 0.0f, 1.0f, 1.0f,

	            // green triangle
	            // X, Y, Z,
	            // R, G, B, A
	    		-1.0f, -1.0f, 0.0f,
	            0.0f, 1.0f, 0.0f, 1.0f,
	 
	            1.0f, -1.0f, 0.0f,
	            0.0f, 1.0f, 0.0f, 1.0f,
	 
	            0.0f, 0.0f, 2.0f,
	            0.0f, 1.0f, 0.0f, 1.0f,
	           
	            // red triangle
	            // X, Y, Z,
	            // R, G, B, A
	    		1.0f, -1.0f, 0.0f,
	            1.0f, 0.0f, 0.0f, 1.0f,
	 
	            1.0f, 1.0f, 0.0f,
	            1.0f, 0.0f, 0.0f, 1.0f,
	 
	            0.0f, 0.0f, 2.0f,
	            1.0f, 0.0f, 0.0f, 1.0f,
	            
	            // yellow triangle
	            // X, Y, Z,
	            // R, G, B, A
	    		1.0f, 1.0f, 0.0f,
	            1.0f, 1.0f, 0.0f, 1.0f,
	 
	            -1.0f, 1.0f, 0.0f,
	            1.0f, 1.0f, 0.0f, 1.0f,
	 
	            0.0f, 0.0f, 2.0f,
	            1.0f, 1.0f, 0.0f, 1.0f,
	            
	            // piramid base
	            // X, Y, Z,
	            // R, G, B, A
	    		1.0f, 1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f,
	 
	            1.0f, -1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f,
	 
	            -1.0f, -1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f,
	            
	            -1.0f, -1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f,
	    
	            -1.0f, 1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f,
	            
	            1.0f, 1.0f, 0.0f,
	            0.5f, 0.5f, 0.5f, 1.0f
	    
		};
	 
	    mPyramid = ByteBuffer.allocateDirect(pyramid.length * mBytesPerFloat)
	    .order(ByteOrder.nativeOrder()).asFloatBuffer();
	    mPyramid.put(pyramid).position(0);
	    
	    pyramidNormalBuffer = ByteBuffer.allocateDirect(18*mPositionDataSize * mBytesPerFloat)
			    .order(ByteOrder.nativeOrder()).asFloatBuffer();
	 float[] normals = new float[18*mPositionDataSize];
	 int pom = 0;
	 int i = 0;
	 for(int j=0; j<6; j++) { 
		 float[] a = {pyramid[pom++],pyramid[pom++],pyramid[pom++]}; pom += 4;
		 float[] b = {pyramid[pom++],pyramid[pom++],pyramid[pom++]}; pom += 4;
		 float[] c = {pyramid[pom++],pyramid[pom++],pyramid[pom++]}; pom += 4;
		 float[] normal = this.TriangleFace(a, b, c);
		 
		 float dl = (float)Math.sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
		 normal[0] = normal[0]/dl;
		 normal[1] = normal[1]/dl;
		 normal[2] = normal[2]/dl;
		 
		 normals[i++] = normal[0];
		 normals[i++] = normal[1];
		 normals[i++] = normal[2];
		 
		 normals[i++] = normal[0];
		 normals[i++] = normal[1];
		 normals[i++] = normal[2];
		 
		 normals[i++] = normal[0];
		 normals[i++] = normal[1];
		 normals[i++] = normal[2];
	 }
	 
	 pyramidNormalBuffer.put(normals).position(0);
	    
	    float[] floor = new float[21*4*(mColorDataSize*mPositionDataSize)];
	    
	    pom = 0;
	    for (i = -10; i <= 10; i++) {
	    	// X, Y, Z,
            // R, G, B, A
	    	floor[pom++] = (float)i; floor[pom++] = -10.0f; floor[pom++] = 0.0f;
			floor[pom++] = 0.3f; floor[pom++] = 1.0f; floor[pom++] = 0.2f; floor[pom++] = 1.0f;
			floor[pom++] = (float)i; floor[pom++] = 10.0f; floor[pom++] = 0.0f;
			floor[pom++] = 0.3f; floor[pom++] = 1.0f; floor[pom++] = 0.2f; floor[pom++] = 1.0f;
			
			floor[pom++] = -10.0f; floor[pom++] = (float)i; floor[pom++] = 0.0f;
			floor[pom++] = 0.3f; floor[pom++] = 1.0f; floor[pom++] = 0.2f; floor[pom++] = 1.0f;
			floor[pom++] = 10.0f; floor[pom++] = (float)i; floor[pom++] = 0.0f;
			floor[pom++] = 0.3f; floor[pom++] = 1.0f; floor[pom++] = 0.2f; floor[pom++] = 1.0f;
		}
	    
	    floorNormalBuffer = ByteBuffer.allocateDirect(floor.length * 3 * mBytesPerFloat)
			    .order(ByteOrder.nativeOrder()).asFloatBuffer();
	    float[] floorNormals = new float[floor.length * 3];
	    for(i=0;i<floor.length;i++) {
	    	floorNormals[0] = 0.0f;
	    	floorNormals[1] = 0.0f;
	    	floorNormals[2] = 1.0f;
	    }
	    floorNormalBuffer.put(floorNormals).position(0);
	    
	    mFloor = ByteBuffer.allocateDirect(floor.length * mBytesPerFloat)
	    		.order(ByteOrder.nativeOrder()).asFloatBuffer();
	    mFloor.put(floor).position(0);
	}
	
	
	public void Tranform(float x, float y) {
		this.transformX += x;
		this.transformY += y;
	}
	
	public void setTransform(float x, float y) {
		this.transformX = x;
		this.transformY = y;
	}
	
	float[] TriangleFace(float[] a, float[] b, float[] c) {
		   float[] normal = new float[3];
		   float[] bMa = new float[3];
		   float[] cMa = new float[3];
		   bMa[0] = b[0]-a[0];
		   bMa[1] = b[1]-a[1];
		   bMa[2] = b[2]-a[2];
		   
		   cMa[0] = c[0] - a[0];
		   cMa[1] = c[1] - a[1];
		   cMa[2] = c[2] - a[2];
		   
		   normal[0] = bMa[1]*cMa[2] - bMa[2]*cMa[1];
		   normal[1] = bMa[2]*cMa[0] - bMa[0]*cMa[2];
		   normal[2] = bMa[0]*cMa[1] - bMa[1]*cMa[0];
		   
		   
		   float dl = (float)Math.sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
		   normal[0] = normal[0]/dl;
		   normal[1] = normal[1]/dl;
		   normal[2] = normal[2]/dl;
	
		   normal[0] = (float)Math.abs(normal[0]);
		   normal[1] = (float)Math.abs(normal[1]);
		   normal[2] = (float)Math.abs(normal[2]);
		   
		   return normal;
		}
	
	private void drawPyramid(final FloatBuffer aPyramidBuffer, GeometryTransform gt)
	{
	    // Pass in the position information
		 aPyramidBuffer.position(mPositionOffset);
		 GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
		           mStrideBytes, aPyramidBuffer);
		 
		 
		 GLES20.glVertexAttribPointer( mNormalHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
				 mPositionDataSize*mBytesPerFloat, pyramidNormalBuffer);
		 
		 GLES20.glEnableVertexAttribArray(mPositionHandle);
		 GLES20.glEnableVertexAttribArray(mNormalHandle);
		    GLES20.glUniform4f(mMaterialAmbientColorLocation, 0.0f, 0.0f, 1.0f,1.0f);
		    GLES20.glUniform4f(mMaterialDiffuseColorLocation, 0.0f, 0.0f, 1.0f,1.0f);
		    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
		    
		    
		  GLES20.glUniform4f(mMaterialAmbientColorLocation, 0.0f, 1.0f, 0.0f,1.0f);
		    GLES20.glUniform4f(mMaterialDiffuseColorLocation, 0.0f, 1.0f, 0.0f,1.0f);
		    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 3, 3);
		    GLES20.glUniform4f(mMaterialAmbientColorLocation, 1.0f, 0.0f, 0.0f,1.0f);
		    GLES20.glUniform4f(mMaterialDiffuseColorLocation, 1.0f, 0.0f, 0.0f,1.0f);
	        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 6, 3);
		    GLES20.glUniform4f(mMaterialAmbientColorLocation, 1.0f, 1.0f, 0.0f,1.0f);
		    GLES20.glUniform4f(mMaterialDiffuseColorLocation, 1.0f, 1.0f, 0.0f,1.0f);
		    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 9, 3);
		    
		    //w GLES20 niestety nie ma sta�ej GLES20.GL_QUADS  
		    GLES20.glUniform4f(mMaterialAmbientColorLocation, 0.5f, 0.5f, 0.5f,1.0f);
		    GLES20.glUniform4f(mMaterialDiffuseColorLocation, 0.5f, 0.5f, 0.5f,1.0f);
		    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 12, 3);
		    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 15, 3);	 
		    GLES20.glDisableVertexAttribArray(mNormalHandle);
	}
	
	private void drawFloor(final FloatBuffer aFloorBuffer) {
		
		 GLES20.glVertexAttribPointer( mNormalHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
				 mPositionDataSize*mBytesPerFloat, floorNormalBuffer);
		 
		 GLES20.glEnableVertexAttribArray(mNormalHandle);
		 
		GLES20.glUniform4f(mMaterialAmbientColorLocation, 0.0f, 0.5f, 0.0f,1.0f);
		GLES20.glUniform4f(mMaterialDiffuseColorLocation, 0.0f, 0.5f, 0.0f,1.0f);
		
		aFloorBuffer.position(mPositionOffset);
		GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mStrideBytes, aFloorBuffer);
		
		GLES20.glEnableVertexAttribArray(mPositionHandle);
		
	    for (int i = 0; i < 42; i++) {
	    	GLES20.glDrawArrays(GLES20.GL_LINES, i*2, 2);
	    }
	    
	    GLES20.glDisableVertexAttribArray(mNormalHandle);
	}
	

	@Override
	public void onDrawFrame(GL10 arg0) {
		GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
		GeometryTransform geometryPipeline = new GeometryTransform();
		
		MatrixStack modelView = new MatrixStack();
		MatrixStack projection = new MatrixStack();
		
		geometryPipeline.SetMatrixStacks(modelView, projection);
		
		projection.pushMatrix();
		//frustrum
		projection.loadMatrix(new Matrix4f(ProjectionMatrix));
		

		final long elapsedTime = Math.abs(System.currentTimeMillis() - this.startTime); 
		float angle = ((float)(elapsedTime * Math.PI))/10000;
		
        final float eyeX = (float) (6.8f * Math.cos(angle)) + this.transformX;
        final float eyeY = (float) (6.0f * Math.sin(angle)) + this.transformY;
        final float eyeZ = 5.0f;
        
        GLES20.glUniform4f(mAmbientLightLocation, 0.5f, 0.5f, 0.5f,1.0f);
        
        GLES20.glUniform4f(mMaterialSpecularColorLocation, 1.0f, 1.0f, 1.0f,1.0f);
        GLES20.glUniform1f(mMaterialSpecularExponentLocation, 200.0f);
     
        final float lookX = 0.0f;
        final float lookY = 0.0f;
        final float lookZ = 0.0f;
     
        final float upX = 0.0f;
        final float upY = 1.0f;
        final float upZ = 0.0f;
     
        Matrix.setLookAtM(CameraMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
		
        Matrix4f mCameraMatrix = new Matrix4f(CameraMatrix);
        modelView.pushMatrix();
        modelView.loadMatrix(mCameraMatrix);
        modelView.pushMatrix();
        
        float[] lightPosition = {1.0f,0.0f,4.0f,1.0f};
        float[] mLightPosInEyeSpace = new float[4];
        Matrix.multiplyMV(mLightPosInEyeSpace, 0, CameraMatrix, 0, lightPosition, 0); 
        
        float[] lightColor = {1.0f,1.0f,1.0f,1.0f};
        
        light1.send(mLightPosInEyeSpace, lightColor, 0.1f, 0.1f, 0.1f);
        
        GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);
        GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		
		drawFloor(mFloor);
		
		modelView.translate(0.0f, 0.0f, 4.0f);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(0.0f, 0.0f, 1.0f);
		modelView.rotate(180.f, 0.0f, 1.0f, 0.0f);
	//	matrixStack.scale(0.5f, 1.0f, 1.0f);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(2.0f, 0.0f, 2.5f);
		modelView.rotate(90.f, 0.0f, 1.0f, 0.0f);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(-2.0f, 0.0f, 2.5f);
		modelView.rotate(90.f, 0.0f, -1.0f, 0.0f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(0.0f, -2.0f, 2.5f);
		modelView.rotate(90.f, 1.0f, 0.0f, 0.0f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(0.0f, 2.0f, 2.5f);
		modelView.rotate(90.f, -1.0f, 0.0f, 0.0f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		//ma�e piramidy
		angle = ((float)(elapsedTime * Math.PI))/700;
		float smallX = (float)(Math.cos(angle)*0.5);
		float smallY = (float)(Math.sin(angle)*0.5);
		
		float smallZ = (float)(Math.sin(((float)(elapsedTime * Math.PI))/1500)*0.5);
		 
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		//matrixStack.rotate(180.f, 0.0f, 1.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		modelView.rotate(180.f, 0.0f, 1.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		modelView.rotate(90.f, 0.0f, 1.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		modelView.rotate(90.f, 0.0f, -1.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		modelView.rotate(90.f, 1.0f, 0.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.pushMatrix();
		modelView.translate(smallX, smallY, 2.5f + smallZ);
		modelView.rotate(90.f, -1.0f, 0.0f, 0.0f);
		modelView.scale(0.5f, 0.5f, 0.5f);
		GLES20.glUniformMatrix4fv(MVMatrixLocation, 1, false, geometryPipeline.getModelView().getMatrix().getArray(), 0);
		GLES20.glUniformMatrix4fv(MVPMatrixLocation, 1, false, geometryPipeline.getModelViewProjectionMatrix().getArray(), 0);	
		drawPyramid(mPyramid,geometryPipeline);
		
		modelView.popMatrix();
		modelView.popMatrix();
		projection.popMatrix();
	}

	@Override
	public void onSurfaceChanged(GL10 arg0, int width, int height) {   
	    GLES20.glViewport(0, 0, width, height);
	    
	    float ratio = (float) width / height;
	    
	    final float left = -ratio;
	    final float right = ratio;
	    final float bottom = -1.0f;
	    final float top = 1.0f;
	    final float near = 1.f;
	    final float far = 100.0f;
	 
	    Matrix.frustumM(ProjectionMatrix, 0, left, right, bottom, top, near, far);
	}

	@Override
	public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
		this.startTime = System.currentTimeMillis();
		
		light1 = new Light();
		
	    GLES20.glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
	    
	    //w��czenie bufora g��boko�ci
	    GLES20.glEnable( GLES20.GL_DEPTH_TEST );
        GLES20.glDepthFunc( GLES20.GL_LEQUAL );
        GLES20.glDepthMask( true );
        
      //ustawienie kierunku tworzenia wierzcho�k�w wielok�t�w
        GLES20.glFrontFace(GLES20.GL_CCW);
        
        //ukrywanie tylnych �cian
        GLES20.glCullFace(GLES20.GL_BACK);
        GLES20.glEnable(GLES20.GL_CULL_FACE); 
        
     
	    
     // Load in the vertex shader.
	    int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
	     
	    if (vertexShaderHandle != 0)
	    {
	        // Pass in the shader source.
	        GLES20.glShaderSource(vertexShaderHandle, vertexShader);
	     
	        // Compile the shader.
	        GLES20.glCompileShader(vertexShaderHandle);
	     
	        // Get the compilation status.
	        final int[] compileStatus = new int[1];
	        GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
	     
	        // If the compilation failed, delete the shader.
	        if (compileStatus[0] == 0)
	        {
	            GLES20.glDeleteShader(vertexShaderHandle);
	            vertexShaderHandle = 0;
	        }
	    }
	    
	 // Load in the vertex shader.
	    int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
	     
	    if (fragmentShaderHandle != 0)
	    {
	        // Pass in the shader source.
	        GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
	     
	        // Compile the shader.
	        GLES20.glCompileShader(fragmentShaderHandle);
	     
	        // Get the compilation status.
	        final int[] compileStatus = new int[1];
	        GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
	     
	        // If the compilation failed, delete the shader.
	        if (compileStatus[0] == 0)
	        {
	            GLES20.glDeleteShader(fragmentShaderHandle);
	            fragmentShaderHandle = 0;
	        }
	    }
	     
	    if (fragmentShaderHandle == 0)
	    {
	        throw new RuntimeException("Error creating fragment shader.");
	    }
	    
	 // Create a program object and store the handle to it.
	    int programHandle = GLES20.glCreateProgram();
	     
	    if (programHandle != 0)
	    {
	        // Bind the vertex shader to the program.
	        GLES20.glAttachShader(programHandle, vertexShaderHandle);
	     
	        // Bind the fragment shader to the program.
	        GLES20.glAttachShader(programHandle, fragmentShaderHandle);
	     
	        // Bind attributes
	        GLES20.glBindAttribLocation(programHandle, 0, "vVertex");
	        GLES20.glBindAttribLocation(programHandle, 1, "a_Normal");
	     
	        // Link the two shaders together into a program.
	        GLES20.glLinkProgram(programHandle);
	     
	        // Get the link status.
	        final int[] linkStatus = new int[1];
	        GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
	     
	        // If the link failed, delete the program.
	        if (linkStatus[0] == 0)
	        {
	            GLES20.glDeleteProgram(programHandle);
	            programHandle = 0;
	        }
	    }
	     
	    if (programHandle == 0)
	    {
	        throw new RuntimeException("Error creating program.");
	    }
	    
	    MVPMatrixLocation = GLES20.glGetUniformLocation(programHandle, "MVPMatrix");
	    if(MVPMatrixLocation == -1) {
	    	throw new RuntimeException("uniform MVPMatrix could not be found");
	    }
	    
	    MVMatrixLocation = GLES20.glGetUniformLocation(programHandle, "MVMatrix");
	    
	    mPositionHandle = GLES20.glGetAttribLocation(programHandle, "vVertex");
	    
	    mNormalHandle = GLES20.glGetAttribLocation(programHandle, "a_Normal");
//	    if(mPositionHandle == -1) {
//	    	throw new RuntimeException("vVertex could not be found");
//	    }
	    
	    mMaterialAmbientColorLocation = GLES20.glGetUniformLocation(programHandle, "material.ambientColor");
	    mMaterialDiffuseColorLocation = GLES20.glGetUniformLocation(programHandle, "material.diffuseColor");
	    mMaterialSpecularColorLocation = GLES20.glGetUniformLocation(programHandle, "material.speculartColor");
	  //  mMaterialSpecularExponentLocation = GLES20.glGetUniformLocation(programHandle, "material.specularExponent");
//	    if(mColorHandle == -1) {
//	    	throw new RuntimeException("vColor could not be found");
//	    }
	    light1.load(programHandle);
	    
	    mAmbientLightLocation = GLES20.glGetUniformLocation(programHandle, "ambientLight");
	    
	    // Tell OpenGL to use this program when rendering.
	    GLES20.glUseProgram(programHandle);
	}
}
